module Lacrima
  
  module Options
    
    class << self

      attr_accessor :parent

      def define_for(mod, &block)
        self.parent = mod
        return if parent.const_defined?("Options")
        create_options_for(parent, &block)
      end
      
      def create_options_for(parent, &block)
        klass = fresh_options_for(parent)
        yield(klass)
      end

      def fresh_options_for(parent)
        child = parent.const_set(:Options, Module.new)
        child.send(:extend, Lacrima::Options::Definition)
      end

    end
    
    module Definition

      attr_accessor :blocks, :option_parser, :options, :arguments

      def defaults(&block)
        add_block(:defaults, &block)
      end

      def usage(&block)
        add_block(:usage) do |op|
          op.set_summary_indent '  '
        end
        add_block(:usage, &block)
      end

      def parser(&block)
        add_block(:parser) do |op, o|
          op.separator ""
          op.separator "  OPTIONS"
          op.separator ""
        end
        add_block(:parser, &block)
        add_block(:parser) do |op, o|
          op.separator ""
        end
      end

      def arguments(&block)
        add_block(:args, &block)
      end
      
      def new(arguments)

        self.arguments = arguments
        self.options = ::OpenStruct.new
        self.options.parser = self.option_parser = ::OptionParser.new

        run(:defaults, options)
        run(:usage, option_parser)
        run(:parser, option_parser, options)
        option_parser.parse!(arguments)
        run(:args, arguments, options)

        options
      end
      
      protected

      def blocks
        @blocks ||= {}
      end
      
      def add_block(key, &block)
        blocks[key] ||= []
        blocks[key] << block
      end
      
      def run(key, *args)
        blocks[key].each { |block| result = block.call(*args) }
      end

    end

  end
end